
#include "zen_metal.id.h"
#include "zen_metal_type.h"
#include "zen_metal_prepare.h"
#include <vector>
#include <map>

namespace Zen { namespace Metal {
	
	typedef std::string VShader;
	typedef std::string FShader;
	
	template<typename _TypeEffect>
	std::shared_ptr<_TypeEffect> sCreateEffect
	(VShader const & vertex, FShader const & fragment,
	 Blends blends)
	{
		auto a = std::shared_ptr<_TypeEffect>(new _TypeEffect);
		a->create(vertex, fragment, blends);
		return a;
	}
	
	template<typename _TypeEffect>
	std::shared_ptr<_TypeEffect> sCreateEffect
	(VShader const & vertex, FShader const & fragment)
	{
		auto a = std::shared_ptr<_TypeEffect>(new _TypeEffect);
		a->create(vertex, fragment);
		return a;
	}
}}

namespace Zen { namespace Metal {

	inline static int sGetIndex(bool grayfy)
	{
		return (grayfy?1:0);
	}
	inline static int sGetIndex(bool grayfy, ePixel fomrat)
	{
		return (fomrat==ePixel::Grey?2:0) | (grayfy?1:0);
	}
	inline static uint64_t sGetBFKey(Blends const & b)
	{
		//if(b.src == eBF::None || b.dst == eBF::None) return (uint64_t)-1;
		return b.value;
	}

	/// pipex
	
	std::shared_ptr<ShaderKitColors> ShaderKitColors::GetShared(bool grayfy, Blends const & blends)
	{
		static std::map<uint64_t, std::shared_ptr<ShaderKitColors> > s_pipes[2];

		static std::string s_pipe_funcs[2][2] = {
			{ "VShaderC", "FShaderC" },
			{ "VShaderC", "FShaderC_g" },
		};
		
		auto index = sGetIndex(grayfy);
		auto key = sGetBFKey(blends);
		auto & sh = s_pipes[index][key];
		if(sh == nullptr)
		{
			sh = sCreateEffect<ShaderKitColors>(s_pipe_funcs[index][0], s_pipe_funcs[index][1], blends);
		}
		return sh;
	}
	
	std::shared_ptr<ShaderKitTexture> ShaderKitTexture::GetShared(bool grayfy, ePixel fomrat, Blends const & blends)
	{
		static std::map<uint64_t, std::shared_ptr<ShaderKitTexture> > s_pipes[4];
		static std::string s_pipe_funcs[4][2] = {
			{ "VShaderT", "FShaderT_RGBA" },
			{ "VShaderT", "FShaderT_RGBAgA" },
			{ "VShaderT", "FShaderT_A" },
			{ "VShaderT", "FShaderT_Ag" },
		};
		
		auto index = sGetIndex(grayfy, fomrat);
		auto key = sGetBFKey(blends);
		auto & sh = s_pipes[index][key];
		if(sh == nullptr)
		{
			sh = sCreateEffect<ShaderKitTexture>(s_pipe_funcs[index][0], s_pipe_funcs[index][1], blends);
		}
		return sh;
	}

	std::shared_ptr<ShaderKitPoints> ShaderKitPoints::GetShared(bool grayfy, Blends const & blends)
	{
		static std::map<uint64_t, std::shared_ptr<ShaderKitPoints> > s_pipes[2];

		static std::string s_pipe_funcs[2][2] = {
			{ "VShaderP", "FShaderP" },
			{ "VShaderP", "FShaderP_g" },
		};
		auto index = sGetIndex(grayfy);
		auto key = sGetBFKey(blends);
		auto & sh = s_pipes[index][key];
		if(sh == nullptr)
		{
			sh = sCreateEffect<ShaderKitPoints>(s_pipe_funcs[index][0], s_pipe_funcs[index][1], blends);
		}
		return sh;
	}

	std::shared_ptr<ShaderKitPT> ShaderKitPT::GetShared(bool grayfy, ePixel fomrat, Blends const & blends)
	{
		static std::map<uint64_t, std::shared_ptr<ShaderKitPT> > s_pipes[4];

		static std::string s_pipe_funcs[4][2] = {
			{ "VShaderP", "FShaderPT_RGBA" },
			{ "VShaderP", "FShaderPT_RGBAgA" },
			{ "VShaderP", "FShaderPT_A" },
			{ "VShaderP", "FShaderPT_Ag" },
		};
		auto index = sGetIndex(grayfy, fomrat);
		auto key = sGetBFKey(blends);
		auto & sh = s_pipes[index][key];

		if(sh == nullptr)
		{
			sh = sCreateEffect<ShaderKitPT>(s_pipe_funcs[index][0], s_pipe_funcs[index][1], blends);
		}
		return sh;
	}


	/// pipex3d



	std::shared_ptr<ShaderKitColors3d> ShaderKitColors3d::GetShared(bool grayfy, Blends const & blends)
	{
		static std::map<uint64_t, std::shared_ptr<ShaderKitColors3d> > s_pipes[2];

		static std::string s_pipe_funcs[2][2] = {
			{ "VShaderC3d", "FShaderC" },
			{ "VShaderC3d", "FShaderC_g" },
		};

		auto index = sGetIndex(grayfy);
		auto key = sGetBFKey(blends);
		auto & sh = s_pipes[index][key];
		if(sh == nullptr)
		{
			sh = sCreateEffect<ShaderKitColors3d>(s_pipe_funcs[index][0], s_pipe_funcs[index][1], blends);
		}
		return sh;
	}

	std::shared_ptr<ShaderKitT3d> ShaderKitT3d::GetShared(bool grayfy, ePixel fomrat, Blends const & blends)
	{
		static std::map<uint64_t, std::shared_ptr<ShaderKitT3d> > s_pipes[4];

		static std::string s_pipe_funcs[4][2] = {
			{ "VShaderT3d", "FShaderT_RGBA" },
			{ "VShaderT3d", "FShaderT_RGBAgA" },
			{ "VShaderT3d", "FShaderT_A" },
			{ "VShaderT3d", "FShaderT_Ag" },
		};

		auto index = sGetIndex(grayfy, fomrat);
		auto key = sGetBFKey(blends);
		auto & sh = s_pipes[index][key];
		if(sh == nullptr)
		{
			sh = sCreateEffect<ShaderKitT3d>(s_pipe_funcs[index][0], s_pipe_funcs[index][1], blends);
		}
		return sh;
	}


	std::shared_ptr<ShaderKitP3d> ShaderKitP3d::GetShared(bool grayfy, Blends const & blends)
	{
		static std::map<uint64_t, std::shared_ptr<ShaderKitP3d> > s_pipes[2];
		static std::string s_pipe_funcs[2][2] = {
			{ "VShaderP3d", "FShaderP" },
			{ "VShaderP3d", "FShaderP_g" },
		};
		auto index = sGetIndex(grayfy);
		auto key = sGetBFKey(blends);
		auto & sh = s_pipes[index][key];
		if(sh == nullptr)
		{
			sh = sCreateEffect<ShaderKitP3d>(s_pipe_funcs[index][0], s_pipe_funcs[index][1], blends);
		}
		return sh;
	}

	std::shared_ptr<ShaderKitPT3d> ShaderKitPT3d::GetShared(bool grayfy, ePixel fomrat, Blends const & blends)
	{
		static std::map<uint64_t, std::shared_ptr<ShaderKitPT3d> > s_pipes[4];
		static std::string s_pipe_funcs[4][2] = {
			{ "VShaderP3d", "FShaderPT_RGBA" },
			{ "VShaderP3d", "FShaderPT_RGBAgA" },
			{ "VShaderP3d", "FShaderPT_A" },
			{ "VShaderP3d", "FShaderPT_Ag" },
		};
		auto index = sGetIndex(grayfy, fomrat);
		auto key = sGetBFKey(blends);
		auto & sh = s_pipes[index][key];
		if(sh == nullptr)
		{
			sh = sCreateEffect<ShaderKitPT3d>(s_pipe_funcs[index][0], s_pipe_funcs[index][1], blends);
		}
		return sh;
	}

}}

namespace Zen { namespace Metal {
}}
